/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "module_common_ipc_stub.h"

#include <stddef.h>

#include "securec.h"

#include "logger.h"
#include "module_common_core.h"
#include "module_common_ipc_defines.h"
#include "module_common_ipc_stub_inner.h"
#include "se_module_common_defines.h"

ResultCode ProcessSeCommonCommandStub(SeCommonContext *context, uint32_t cmd, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("param error, null input");
        return INVALID_PARA_NULL_PTR;
    }

    switch (cmd & 0xFFFF) {
        case CMD_IS_SERVICE_AVAILABLE:
            return ProcessSeCommonIsServiceAvailableStub(context->channel, buffer);
        case CMD_SET_SERVICE_CONFIG:
            return ProcessSeCommonSetServiceConfigurationStub(context->channel, buffer);
        default:
            LOG_ERROR("invoked invalid cmd=0x%x", cmd);
            return INVALID_PARA_ERR_CMD;
    }

    LOG_ERROR("unreachable code");
    return INVALID_PARA_ERR_CMD;
}

ResultCode ProcessSeManagerCommandStub(SeManagerContext *context, uint32_t cmd, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("param error, null input");
        return INVALID_PARA_NULL_PTR;
    }
    switch (cmd) {
        case CMD_SET_BINDING_KEY:
            return ProcessSeCommonSetBindingKeyStub(context, buffer);
        case CMD_DELETE_INIT_KEY:
            return ProcessSeCommonDeleteInitKeyStub(context, buffer);
        default:
            LOG_ERROR("invoked invalid cmd=0x%x", cmd);
            return INVALID_PARA_ERR_CMD;
    }
    LOG_ERROR("unreachable code");
    return INVALID_PARA_ERR_CMD;
}

ResultCode ProcessSeCommonIsServiceAvailableStub(CardChannel *channel, SharedDataBuffer *buffer)
{
    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(ServiceId)) {
        LOG_ERROR("buffer size is invalid");
        return INVALID_PARA_ERR_SIZE;
    }

    if (buffer->dataMaxSize < sizeof(SeServiceStatus)) {
        LOG_ERROR("buffer max is invalid");
        return INVALID_PARA_ERR_SIZE;
    }

    ServiceId sid = *(ServiceId *)buffer->data;

    SeServiceStatus status;
    (void)memset_s(&status, sizeof(SeServiceStatus), 0, sizeof(SeServiceStatus));

    ResultCode ret = SeCommonIsServiceAvailable(channel, sid, &status);
    if (ret != SUCCESS) {
        LOG_ERROR("ProcessSeCommonIsServiceAvailable for sid 0x%x failed, ret is %u", (uint32_t)sid, ret);
        return ret;
    }

    if (memcpy_s(buffer->data, buffer->dataMaxSize, &status, sizeof(SeServiceStatus)) != EOK) {
        LOG_ERROR("memcpy failed");
        return MEM_COPY_ERR;
    }

    buffer->dataSize = sizeof(SeServiceStatus);
    return SUCCESS;
}

ResultCode ProcessSeCommonSetServiceConfigurationStub(CardChannel *channel, SharedDataBuffer *buffer)
{
    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(SeCommonSetServiceConfInput)) {
        LOG_ERROR("buffer size is invalid");
        return INVALID_PARA_ERR_SIZE;
    }

    SeCommonSetServiceConfInput *input = (SeCommonSetServiceConfInput *)buffer->data;
    ResultCode ret = SeCommonSetServiceConfiguration(channel, input->sid, input->lock, &input->config);
    if (ret != SUCCESS) {
        LOG_ERROR("SeCommonSetServiceConfiguration for sid 0x%x failed, ret is %u", (uint32_t)input->sid, ret);
        return ret;
    }

    buffer->dataSize = 0;
    return SUCCESS;
}

ResultCode ProcessSeCommonSetBindingKeyStub(SeManagerContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(SeCommonSetBindingKeyInput)) {
        LOG_ERROR("buffer size is invalid");
        return INVALID_PARA_ERR_SIZE;
    }

    SeCommonSetBindingKeyInput *input = (SeCommonSetBindingKeyInput *)buffer->data;

    CardChannel *channel = context->base.channel;
    SetBindingKey *setBindingKey = context->setBindingKey;
    if (channel == NULL || setBindingKey == NULL) {
        LOG_ERROR("channel or binding is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    ResultCode ret = setBindingKey(channel, input->sid, input->initKey, input->initKeyLength, input->initKvn);
    if (ret != SUCCESS) {
        LOG_ERROR("SeCommonSetBindingKey for sid 0x%x failed, ret is %u", (uint32_t)input->sid, ret);
        return ret;
    }

    buffer->dataSize = 0;
    return SUCCESS;
}

ResultCode ProcessSeCommonDeleteInitKeyStub(SeManagerContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(uint32_t)) {
        LOG_ERROR("buffer size is invalid");
        return INVALID_PARA_ERR_SIZE;
    }

    uint32_t kvn = *(uint32_t *)buffer->data;

    CardChannel *channel = context->base.channel;
    DeleteInitKey *deleteInitKey = context->deleteInitKey;
    if (channel == NULL || deleteInitKey == NULL) {
        LOG_ERROR("channel or binding is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    ResultCode ret = deleteInitKey(channel, NULL, 0, kvn);
    if (ret != SUCCESS) {
        LOG_ERROR("SeCommonDeleteInitKey failed, ret is %u", ret);
        return ret;
    }

    buffer->dataSize = 0;
    return SUCCESS;
}